package com.eudon.user.common.utils;

import com.eudon.user.annotation.CustomValid;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.regex.Pattern;

import static com.eudon.user.common.RegularExpressions.*;

/**
 * @author eudon
 * @description 自定义校验器实现
 * @date 2025/9/8
 * @email syd19970616@gmail.com
 * @address <a href="https://gitee.com/eudon">Gitee</a>
 */
public class CustomValidValidator implements ConstraintValidator<CustomValid, Object> {
    
    private CustomValid annotation;
    
    /**
     * 初始化校验器，保存注解实例以便后续使用
     * @param constraintAnnotation 自定义校验注解实例
     */
    @Override
    public void initialize(CustomValid constraintAnnotation) {
        this.annotation = constraintAnnotation;
    }
    
    /**
     * 执行校验逻辑的核心方法
     * @param value 待校验的值
     * @param context 校验上下文，用于构建错误消息
     * @return true表示校验通过，false表示校验失败
     */
    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        // 禁用默认错误消息
        context.disableDefaultConstraintViolation();
        
        CustomValid.ValidationType[] types = annotation.types();
        boolean isValid = true;
        
        // 遍历所有配置的校验类型，收集所有错误信息
        for (CustomValid.ValidationType type : types) {
            boolean typeValid = validateByType(value, type, context);
            if (!typeValid) {
                isValid = false;
                // 不要立即返回，继续检查其他类型以收集所有错误
            }
        }
        
        return isValid;
    }
    
    /**
     * 根据校验类型执行相应的校验逻辑
     * @param value 待校验的值
     * @param type 校验类型枚举
     * @param context 校验上下文
     * @return true表示该类型校验通过，false表示校验失败
     */
    private boolean validateByType(Object value, CustomValid.ValidationType type, ConstraintValidatorContext context) {
        return switch (type) {
            case NOT_NULL -> validateNotNull(value, context);
            case NOT_BLANK -> validateNotBlank(value, context);
            case NOT_EMPTY -> validateNotEmpty(value, context);
            case EMAIL -> validateEmail(value, context);
            case LENGTH -> validateLength(value, context);
            case RANGE -> validateRange(value, context);
            case PATTERN -> validatePattern(value, context);
            case PHONE -> validatePhone(value, context);
            case ID_CARD -> validateIdCard(value, context);
        };
    }
    
    /**
     * 非空校验：检查值是否为null
     * @param value 待校验的值
     * @param context 校验上下文
     * @return true表示值不为null，false表示值为null
     */
    private boolean validateNotNull(Object value, ConstraintValidatorContext context) {
        if (value == null) {
            context.buildConstraintViolationWithTemplate(annotation.notNullMessage())
                   .addConstraintViolation();
            return false;
        }
        return true;
    }
    
    /**
     * 非空白校验：检查字符串是否为null、空字符串或只包含空白字符
     * @param value 待校验的值
     * @param context 校验上下文
     * @return true表示字符串有实际内容，false表示字符串为空白
     */
    private boolean validateNotBlank(Object value, ConstraintValidatorContext context) {
        if (value == null || (value instanceof String && !StringUtils.hasText((String) value))) {
            context.buildConstraintViolationWithTemplate(annotation.notBlankMessage())
                   .addConstraintViolation();
            return false;
        }
        return true;
    }
    
    /**
     * 非空集合校验：检查集合或字符串是否为空
     * @param value 待校验的值（可以是Collection或String）
     * @param context 校验上下文
     * @return true表示集合/字符串不为空，false表示为空
     */
    private boolean validateNotEmpty(Object value, ConstraintValidatorContext context) {
        if (value == null || 
            (value instanceof Collection && ((Collection<?>) value).isEmpty()) ||
            (value instanceof String && ((String) value).isEmpty())) {
            context.buildConstraintViolationWithTemplate(annotation.notEmptyMessage())
                   .addConstraintViolation();
            return false;
        }
        return true;
    }
    
    /**
     * 邮箱格式校验：使用正则表达式验证邮箱格式
     * @param value 待校验的值
     * @param context 校验上下文
     * @return true表示邮箱格式正确，false表示格式错误
     */
    private boolean validateEmail(Object value, ConstraintValidatorContext context) {
        if (value == null) return true; // null值由NOT_NULL校验处理
        
        if (!(value instanceof String email)) {
            context.buildConstraintViolationWithTemplate(annotation.emailMessage())
                   .addConstraintViolation();
            return false;
        }

        if (!Pattern.matches(EMAIL_PATTERN, email)) {
            context.buildConstraintViolationWithTemplate(annotation.emailMessage())
                   .addConstraintViolation();
            return false;
        }
        return true;
    }
    
    /**
     * 字符串长度校验：检查字符串长度是否在指定范围内
     * @param value 待校验的值
     * @param context 校验上下文
     * @return true表示长度符合要求，false表示长度超出范围
     */
    private boolean validateLength(Object value, ConstraintValidatorContext context) {
        if (value == null) return true; // null值由NOT_NULL校验处理
        
        if (!(value instanceof String str)) {
            context.buildConstraintViolationWithTemplate(annotation.lengthMessage())
                   .addConstraintViolation();
            return false;
        }

        int length = str.length();
        
        if (length < annotation.minLength() || length > annotation.maxLength()) {
            String message = String.format("%s（长度应在%d-%d之间，当前长度：%d）", 
                annotation.lengthMessage(), annotation.minLength(), annotation.maxLength(), length);
            context.buildConstraintViolationWithTemplate(message)
                   .addConstraintViolation();
            return false;
        }
        return true;
    }
    
    /**
     * 数值范围校验：检查数值是否在指定范围内
     * @param value 待校验的值（必须是Number类型）
     * @param context 校验上下文
     * @return true表示数值在范围内，false表示超出范围或类型错误
     */
    private boolean validateRange(Object value, ConstraintValidatorContext context) {
        if (value == null){
            context.buildConstraintViolationWithTemplate(annotation.notNullMessage())
                    .addConstraintViolation();
            return false;
        }
        
        if (!(value instanceof Number)) {
            context.buildConstraintViolationWithTemplate(annotation.rangeMessage())
                   .addConstraintViolation();
            return false;
        }
        
        long numValue = ((Number) value).longValue();
        
        if (numValue < annotation.minValue() || numValue > annotation.maxValue()) {
            String message = String.format("%s（值应在%d-%d之间，当前值：%d）", 
                annotation.rangeMessage(), annotation.minValue(), annotation.maxValue(), numValue);
            context.buildConstraintViolationWithTemplate(message)
                   .addConstraintViolation();
            return false;
        }
        return true;
    }
    
    private boolean validatePattern(Object value, ConstraintValidatorContext context) {
        if (value == null){
            context.buildConstraintViolationWithTemplate(annotation.notNullMessage())
                    .addConstraintViolation();
            return false;
        }
        
        if (!(value instanceof String str)) {
            context.buildConstraintViolationWithTemplate(annotation.patternMessage())
                   .addConstraintViolation();
            return false;
        }

        String regexp = annotation.regexp();
        
        if (StringUtils.hasText(regexp) && !Pattern.matches(regexp, str)) {
            context.buildConstraintViolationWithTemplate(annotation.patternMessage())
                   .addConstraintViolation();
            return false;
        }
        return true;
    }
    
    private boolean validatePhone(Object value, ConstraintValidatorContext context) {
        if (value == null){
            context.buildConstraintViolationWithTemplate(annotation.notNullMessage())
                    .addConstraintViolation();
            return false;
        }
        
        if (!(value instanceof String phone)) {
            context.buildConstraintViolationWithTemplate(annotation.phoneMessage())
                   .addConstraintViolation();
            return false;
        }

        if (!Pattern.matches(PHONE_PATTERN, phone)) {
            context.buildConstraintViolationWithTemplate(annotation.phoneMessage())
                   .addConstraintViolation();
            return false;
        }
        return true;
    }
    
    private boolean validateIdCard(Object value, ConstraintValidatorContext context) {
        if (value == null){
            context.buildConstraintViolationWithTemplate(annotation.notNullMessage())
                    .addConstraintViolation();
            return false;
        }
        
        if (!(value instanceof String idCard)) {
            context.buildConstraintViolationWithTemplate(annotation.idCardMessage())
                   .addConstraintViolation();
            return false;
        }

        if (!Pattern.matches(ID_CARD_PATTERN, idCard)) {
            context.buildConstraintViolationWithTemplate(annotation.idCardMessage())
                   .addConstraintViolation();
            return false;
        }
        return true;
    }
}